import { shallowReadonly } from "../reactivity/reactive";
import { proxyRefs } from "../reactivity/ref";
import { isObject } from "../shared/index";
import { initProps } from "./componentProps";
import { emit } from "./componentEmit";
import { PublicInstanceProxyHandlers } from "./componentPublicInstance";
import { initSlots } from "./componentSlots";

/**
 * 全局当前组件实例对象
 */
var currentInstance;

export function createComponentInstance(vnode: any, parentComponent) {
    console.log("createComponentInstance", parentComponent)
    // vnode 挂载到一个 component 对象上
    const component = {
        vnode,
        type: vnode.type,
        setupState: {},
        props: {},
        emit: () => { },
        slots: {},
        provides: parentComponent ? parentComponent.provides : {},
        parent: parentComponent,
        subTree :{}, // render 后的节点树，用于update 比较，在 update 时，改属性一般代表上一次渲染的的节点树
    }

    // emit 挂载到组件实例上, emit 的第一个参数的实参设置为 component 
    component.emit = emit.bind('', component) as any;
    return component;
}

export function setupComponent(instance: any) {
    // 这里初始化 props ，插槽
    /// todo: initProps 
    initProps(instance, instance.vnode.props);
    /// todo: initSlots 
    initSlots(instance, instance.vnode.children);


    // 初始化一个有状态的 Component
    // 这里先初始化 render 函数 (该方法调用完后，最终 instance 上将会有个 render 方法)
    setupStatefulComponent(instance);
}

function setupStatefulComponent(instance: any) {
    // 获取对象属性
    const Component = instance.type;
    // 获取 setup 方法
    const { setup } = Component;

    if (setup) {
        // setup 开始，全局当前实例对象设置为 instance 
        setCurrentInstance(instance);
        // 调用 setup ， 传入 props 给组件， 获取到 setup 函数的返回值
        // setup 传入的 props 需要是一个 shallowReadonly 对象
        const setupResult = setup(shallowReadonly(instance.props), { emit: instance.emit });

        // 如果 setupResult 是一个 function 认为这个 function 为组件 component 的 render 函数
        // 如果 setupResult 是一个 object ，把这个 object 注入到组件上下文中
        handleSetupResult(instance, setupResult);

        // setup 结束，全局当前实例对象设置为 null 
        setCurrentInstance(null);
    }

}

function handleSetupResult(instance, setupResult: any) {
    if (!setupResult) {
        console.error(`组件 setup 没有返回任何方法或者对象`, instance);
        return;
    }
    if (isObject(setupResult)) {
        // 把 setupResult 挂载到实例上, 使用proxyRefs让 render 中可以不用.value 访问
        instance.setupState = proxyRefs(setupResult);
        // 上下文对象 
        instance.proxy = new Proxy({ _: instance }, PublicInstanceProxyHandlers)
    } else {
        // setupResult 是 function 的情况
    }

    // 保证组件的 render 是有值的
    // 设置 instance 实例的 render
    finishComponentSetup(instance)
}

function finishComponentSetup(instance: any) {
    // 获取对象属性
    const Component = instance.type;

    // 检查组件上是否有（写了） render 函数
    if (Component.render) {
        // 有写了 render 的情况时 ，给 instance 实例的 render 赋值
        instance.render = Component.render;
    }
}

/**
 * 获取当前全局组件实例对象
 * @returns 当前全局组件实例对象
 */
export function getCurrentInstance() {
    return currentInstance;
}


/**
 * 设置当前全局组件实例对象
 * @params value 设置给当前全局组件实例对象的新值
 */
export function setCurrentInstance(value) {
    currentInstance = value;
}

